﻿// -------------------------------------------------------------------------------------------------------
// LICENSE INFORMATION
//
// - This software is licensed under the MIT shared source license.
// - The "official" source code for this project is maintained at http://mtcagent.codeplex.com
//
// Copyright (c) 2010 OpenNETCF Consulting
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
// associated documentation files (the "Software"), to deal in the Software without restriction, 
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial 
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
// -------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.IO;
using System.Reflection;
using OpenNETCF.IoC;
using System.Diagnostics;
using System.Xml.Linq;
using System.Threading;
using System.Security.Policy;
using System.Net;

#if WindowsCE
using OpenNETCF.WindowsCE.Messaging;
using OpenNETCF.Threading;
#endif

namespace OpenNETCF.MTConnect
{
    internal class IPCService : DisposableBase
    {
#if WindowsCE
        public const string ServiceRunningMutexName = "MTC_IPCService_Mutex";
        public const string RxQueueName = "MTC_IPCService_RxQueue";
        public const int MaxMessageSize = 1024;
        public const int MaxMessageCount = 100;

        private P2PMessageQueue m_listenQueue;
        private NamedMutex m_upMutex;

        private IMTConnectProvider Provider { get; set; }

        [InjectionConstructor]
        public IPCService([ServiceDependency] IMTConnectProvider provider)
        {
            Provider = provider;

            m_listenQueue = new P2PMessageQueue(true, RxQueueName, MaxMessageSize, MaxMessageCount);
            m_listenQueue.DataOnQueueChanged += new EventHandler(m_listenQueue_DataOnQueueChanged);

            m_upMutex = new NamedMutex(true, ServiceRunningMutexName);

        }

        void m_listenQueue_DataOnQueueChanged(object sender, EventArgs e)
        {
            var message = new PublishMessage();

            while (m_listenQueue.MessagesInQueueNow > 0)
            {
                var result = m_listenQueue.Receive(message, 1000);
                if (result == ReadWriteResult.OK)
                {
                    ProcessPublishMessage(message);
                }
            }
        }

        private void ProcessPublishMessage(PublishMessage message)
        {
            try
            {
                Provider.SetDataByDataItemID("IPCService", message.DataItemID, message.DataItemValue);
            }
            catch (InvalidIDException)
            {
                if (Debugger.IsAttached) Debugger.Break();

                // the ID doesn't exist - ignore it (todo: cache known bad IDs so we don't continually get the exception)
            }
        }

        protected override void ReleaseNativeResources()
        {
            if (m_upMutex != null)
            {
                m_upMutex.Close();
            }

            if (m_listenQueue != null)
            {
                m_listenQueue.Close();
            }
        }

        private class PublishMessage : Message
        {
            public string DataItemID 
            {
                get
                {
                    return Encoding.ASCII.GetString(MessageBytes, 0, 512).Trim('\0');
                }
            }
            public string DataItemValue
            {
                get
                {
                    return Encoding.ASCII.GetString(MessageBytes, 512, 512).Trim('\0');
                }
            }
        }
#else
        // stub for desktop implementation
        public IPCService()
        {
        }
#endif
    }
}
